"""
通知服务
"""

import asyncio
import smtplib
from typing import  datetime
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from typing import  encoders
from pathlib import Path
from typing import  List, Dict, Any, Optional
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from models.notification import NotificationConfig, Notification
from models.execution import Execution
from models.task import Task
from config import settings
from utils.logger import get_logger

logger = get_logger(__name__)


class NotificationService:
    """通知服务"""

    def __init__(self):
        self.email_config = settings.get_email_config()
        self.enabled = settings.is_email_enabled

    async def send_task_notification(
        self,
        execution_id: int,
        event_type: str,  # success, failure, started
        db: AsyncSession
    ) -> List[Notification]:
        """发送任务通知"""
        if not self.enabled:
            logger.warning("邮件通知未启用，跳过发送")
            return []

        try:
            # 获取执行记录
            execution = await db.get(Execution, execution_id)
            if not execution:
                logger.error("执行记录不存在", execution_id=execution_id)
                return []

            # 获取任务信息
            task = await db.get(Task, execution.task_id)
            if not task:
                logger.error("任务不存在", task_id=execution.task_id)
                return []

            # 查询相关的通知配置
            stmt = select(NotificationConfig).where(
                NotificationConfig.task_id == task.id,
                NotificationConfig.is_active == True
            )
            result = await db.execute(stmt)
            notification_configs = result.scalars().all()

            notifications = []

            for config in notification_configs:
                # 检查是否需要发送此事件类型的通知
                if not config.has_event(event_type):
                    continue

                if config.is_email_config:
                    notification = await self._send_email_notification(
                        config=config,
                        execution=execution,
                        task=task,
                        event_type=event_type,
                        db=db
                    )
                    if notification:
                        notifications.append(notification)

            logger.info(
                "任务通知发送完成",
                execution_id=execution_id,
                event_type=event_type,
                notifications_count=len(notifications)
            )

            return notifications

        except Exception as e:
            logger.error("发送任务通知失败", execution_id=execution_id, error=str(e))
            return []

    async def _send_email_notification(
        self,
        config: NotificationConfig,
        execution: Execution,
        task: Task,
        event_type: str,
        db: AsyncSession
    ) -> Optional[Notification]:
        """发送邮件通知"""
        try:
            recipients = config.get_recipients()
            if not recipients:
                logger.warning("没有配置收件人", config_id=config.id)
                return None

            # 生成邮件内容
            subject, content = await self._generate_email_content(
                task=task,
                execution=execution,
                event_type=event_type
            )

            # 创建通知记录
            notifications = []
            for recipient in recipients:
                notification = Notification(
                    execution_id=execution.id,
                    config_id=config.id,
                    type="email",
                    recipient=recipient,
                    subject=subject,
                    content=content,
                    status="pending"
                )
                db.add(notification)
                notifications.append(notification)

            await db.commit()

            # 发送邮件
            await self._send_email(
                recipients=recipients,
                subject=subject,
                content=content
            )

            # 更新通知状态为已发送
            for notification in notifications:
                notification.mark_as_sent()

            await db.commit()

            logger.info(
                "邮件通知发送成功",
                config_id=config.id,
                execution_id=execution.id,
                recipients_count=len(recipients)
            )

            return notifications[0] if notifications else None

        except Exception as e:
            # 更新通知状态为失败
            if 'notifications' in locals():
                for notification in notifications:
                    notification.mark_as_failed(str(e))

                await db.commit()

            logger.error(
                "邮件通知发送失败",
                config_id=config.id,
                execution_id=execution.id,
                error=str(e)
            )
            return None

    async def _generate_email_content(
        self,
        task: Task,
        execution: Execution,
        event_type: str
    ) -> tuple[str, str]:
        """生成邮件内容"""
        if event_type == "success":
            subject = f"[Tete1] 同步任务执行成功 - {task.name}"
            content = await self._generate_success_email_content(task, execution)
        elif event_type == "failure":
            subject = f"[Tete1] 同步任务执行失败 - {task.name}"
            content = await self._generate_failure_email_content(task, execution)
        elif event_type == "started":
            subject = f"[Tete1] 同步任务开始执行 - {task.name}"
            content = await self._generate_started_email_content(task, execution)
        else:
            subject = f"[Tete1] 同步任务状态更新 - {task.name}"
            content = await self._generate_default_email_content(task, execution, event_type)

        return subject, content

    async def _generate_success_email_content(self, task: Task, execution: Execution) -> str:
        """生成成功邮件内容"""
        content = f"""
任务执行成功！

任务名称: {task.name}
执行时间: {execution.start_time}
执行时长: {execution.duration} 秒
成功仓库数: {execution.successful_targets}
失败仓库数: {execution.failed_targets}

执行详情:
"""

        for result in execution.target_results:
            status_icon = "✅" if result.get("status") == "success" else "❌"
            content += f"{status_icon} {result.get('repo_name', '未知仓库')}: {result.get('message', '无消息')}\\n"

        content += f"\\n提交ID: {execution.source_commit}"
        content += "\\n\\n此邮件由 Tete1 Git同步系统自动发送"

        return content

    async def _generate_failure_email_content(self, task: Task, execution: Execution) -> str:
        """生成失败邮件内容"""
        content = f"""
任务执行失败！

任务名称: {task.name}
执行时间: {execution.start_time}
错误信息: {execution.error_message}

执行详情:
"""

        for result in execution.target_results:
            status_icon = "✅" if result.get("status") == "success" else "❌"
            content += f"{status_icon} {result.get('repo_name', '未知仓库')}: {result.get('message', '无消息')}\\n"

        if execution.error_details:
            content += f"\\n错误详情:\\n{execution.error_details}"

        # 添加日志查看链接
        content += f"\\n\\n查看详细日志: http://localhost/api/v1/executions/{execution.id}/logs"
        content += "\\n\\n此邮件由 Tete1 Git同步系统自动发送"

        return content

    async def _generate_started_email_content(self, task: Task, execution: Execution) -> str:
        """生成开始执行邮件内容"""
        content = f"""
任务开始执行！

任务名称: {task.name}
开始时间: {execution.start_time}
源分支: {execution.branch_mapping.get('source_branch', 'main')}

目标仓库:
"""

        for repo_info in task.target_repos:
            content += f"- {repo_info.get('name', '未知仓库')}\\n"

        content += "\\n此邮件由 Tete1 Git同步系统自动发送"

        return content

    async def _generate_default_email_content(self, task: Task, execution: Execution, event_type: str) -> str:
        """生成默认邮件内容"""
        content = f"""
任务状态更新！

任务名称: {task.name}
状态: {execution.status}
更新时间: {execution.updated_at}

此邮件由 Tete1 Git同步系统自动发送
"""

        return content

    async def _send_email(
        self,
        recipients: List[str],
        subject: str,
        content: str,
        attachments: Optional[List[Dict[str, Any]]] = None
    ) -> None:
        """发送邮件"""
        if not self.email_config:
            raise ValueError("邮件配置未设置")

        try:
            # 创建邮件消息
            msg = MIMEMultipart()
            msg['From'] = self.email_config["from_address"]
            msg['To'] = ", ".join(recipients)
            msg['Subject'] = subject

            # 添加邮件正文
            msg.attach(MIMEText(content, 'plain', 'utf-8'))

            # 添加附件
            if attachments:
                for attachment in attachments:
                    await self._add_email_attachment(msg, attachment)

            # 发送邮件
            with smtplib.SMTP(
                self.email_config["host"],
                self.email_config["port"]
            ) as server:
                if self.email_config.get("use_tls", True):
                    server.starttls()

                server.login(
                    self.email_config["username"],
                    self.email_config["password"]
                )

                server.send_message(msg)

            logger.info(
                "邮件发送成功",
                recipients=recipients,
                subject=subject
            )

        except Exception as e:
            logger.error(
                "邮件发送失败",
                recipients=recipients,
                subject=subject,
                error=str(e)
            )
            raise

    async def _add_email_attachment(self, msg: MIMEMultipart, attachment: Dict[str, Any]) -> None:
        """添加邮件附件"""
        try:
            file_path = Path(attachment["path"])
            if not file_path.exists():
                logger.warning("附件文件不存在", file_path=str(file_path))
                return

            with open(file_path, "rb") as f:
                part = MIMEBase('application', 'octet-stream')
                part.set_payload(f.read())

            encoders.encode_base64(part)
            part.add_header(
                'Content-Disposition',
                f'attachment; filename= {attachment.get("name", file_path.name)}'
            )

            msg.attach(part)

        except Exception as e:
            logger.error("添加邮件附件失败", attachment=attachment, error=str(e))

    async def test_email_configuration(self, recipient: str) -> Dict[str, Any]:
        """测试邮件配置"""
        try:
            if not self.enabled:
                return {
                    "success": False,
                    "message": "邮件功能未启用"
                }

            await self._send_email(
                recipients=[recipient],
                subject="Tete1 邮件配置测试",
                content="这是一封测试邮件，用于验证邮件配置是否正确。\\n\\n如果您收到此邮件，说明邮件配置正常工作。"
            )

            return {
                "success": True,
                "message": "测试邮件发送成功",
                "recipient": recipient,
                "sent_at": datetime.utcnow().isoformat()
            }

        except Exception as e:
            logger.error("邮件配置测试失败", recipient=recipient, error=str(e))
            return {
                "success": False,
                "message": f"测试失败: {str(e)}",
                "recipient": recipient
            }

    async def get_notification_status(self, execution_id: int, db: AsyncSession) -> Dict[str, Any]:
        """获取通知状态"""
        try:
            stmt = select(Notification).where(Notification.execution_id == execution_id)
            result = await db.execute(stmt)
            notifications = result.scalars().all()

            status = {
                "total": len(notifications),
                "sent": len([n for n in notifications if n.is_sent]),
                "failed": len([n for n in notifications if n.is_failed]),
                "pending": len([n for n in notifications if n.is_pending]),
                "notifications": []
            }

            for notification in notifications:
                status["notifications"].append({
                    "id": notification.id,
                    "type": notification.type,
                    "recipient": notification.recipient,
                    "status": notification.status,
                    "sent_at": notification.sent_at.isoformat() if notification.sent_at else None,
                    "error_message": notification.error_message
                })

            return status

        except Exception as e:
            logger.error("获取通知状态失败", execution_id=execution_id, error=str(e))
            return {
                "total": 0,
                "sent": 0,
                "failed": 0,
                "pending": 0,
                "notifications": [],
                "error": str(e)
            }


# 全局通知服务实例
notification_service = NotificationService()